<!--
 * hi-notice-bar - 滚动通知
 *
 * @author 济南晨霜信息技术有限公司
 * @mobile 18560000860 / 18754137913
 -->
<template>
    <view class="hi-notice-bar" :class="_classes" :style="_styles" v-if="isShow" @animationend.stop="onComponentAnimationEnd">
        <!-- 左侧通知图标 -->
        <hi-icon class="hi-notice-bar__icon hi-notice-bar__icon--notice" :name="iconName" v-if="icon"></hi-icon>

        <!-- 内容区域 -->
        <view class="hi-notice-bar__content">
            <view
                class="hi-notice-bar__text"
                :class="`${_index === current ? 'hi-notice-bar__text--move-to' : ''} ${_textClasses}`"
                :style="textsStyles[_index]"
                v-for="(_item, _index) in list"
                :key="_index"
                @animationend.stop="onAnimationEnd(_index)"
                @tap="_emits('itemClick', _item, _index)"
                :hover-class="hover"
            >
                {{ _item[keyName] }}
            </view>
        </view>

        <!-- 更多 -->
        <hi-icon
            class="hi-notice-bar__icon hi-notice-bar__icon--arrow"
            :name="arrowIcon"
            v-if="arrow"
            @tap="_emits('arrow', current)"
            :hover-class="hover"
        ></hi-icon>

        <!-- 关闭 -->
        <hi-icon class="hi-notice-bar__icon hi-notice-bar__icon--close" :name="closeIcon" v-if="close" @tap="_emits('close')" :hover-class="hover"></hi-icon>
    </view>
</template>

<!-- 由于 HbuilderX 不支持 defineOptions() 写法，故只能在此处进行配置 -->
<script>
    export default { options: uni?.$hi?.config?.componentsOptions || {} };
</script>

<script setup>
    import { ref, computed, onMounted, getCurrentInstance, nextTick, watch } from "vue";
    import props from "./props.js";
    import { sleep, uniGetNodesRectInfo } from "../../functions";

    // 组件实例
    const instance = getCurrentInstance();

    // 组件属性
    const _props = defineProps(props);

    // 组件事件
    const _emits = defineEmits(["itemClick", "arrow", "close"]);

    // 组件类名
    const _classes = computed(() => {
        const classes = [];

        // 显示状态
        if (_props.show) classes.push(`hi-notice-bar--show`);
        else classes.push(`hi-notice-bar--hide`);

        // 纵向
        if (_props.vertical) classes.push(`hi-notice-bar--column`);
        else classes.push(`hi-notice-bar--row`);

        // 步进式滚动
        if (_props.step) classes.push(`hi-notice-bar--step`);

        return classes;
    });

    // 组件样式
    const _styles = computed(() => {
        const styles = [];

        // 图标颜色、大小
        if (_props.iconColor) styles.push(`hi-notice-bar-icon-color: ${_props.iconColor}`);
        if (_props.iconSize) styles.push(`hi-notice-bar-icon-font-size: ${_props.iconSize}`);

        // 箭头颜色、大小
        if (_props.arrowColor) styles.push(`hi-notice-bar-arrow-color: ${_props.arrowColor}`);
        if (_props.arrowSize) styles.push(`hi-notice-bar-arrow-font-size: ${_props.arrowSize}`);

        // 关闭按钮颜色、大小
        if (_props.closeColor) styles.push(`hi-notice-bar-close-color: ${_props.closeColor}`);
        if (_props.closeSize) styles.push(`hi-notice-bar-close-font-size: ${_props.closeSize}`);

        return styles;
    });

    // 滚动文字元素的类名
    const _textClasses = computed(() => {
        const classes = [];

        // 步进式滚动时锁定文本为 1 行
        if (_props.step) classes.push(`hi-line-${_props.lines}`);

        return classes.join(" ");
    });

    // 当前滚动通知的下标
    const current = ref(-1);

    // 所有通知的布局信息
    const rects = ref([]);

    // 监听数据列表后重新初始化
    watch(
        () => _props.list,
        () => {
            init();
        },
        {
            deep: true,
            immediate: true
        }
    );

    // 显示状态
    const isShow = ref(_props.show);

    // 显示/隐藏的时候添加过渡效果
    watch(
        () => _props.show,
        (newVal) => {
            if (newVal) isShow.value = true;
        }
    );

    // 初始化
    async function init() {
        // 等待数据渲染完成
        await nextTick();

        // 数据更新完后稍微延时一下再开始
        await sleep(80);

        // 获取所有通知的布局信息
        await getRects();

        // 只有一条数据时得切换一下下标为-1后再重新运行
        current.value = -1;

        // 同样的等一下
        await nextTick();
        await sleep(20);

        // 重新运行
        current.value = 0;
    }

    // 获取所有通知的布局信息
    function getRects() {
        return uniGetNodesRectInfo(".hi-notice-bar__text", instance).then((res) => {
            rects.value = res || [];
        });
    }

    // 过渡结束事件
    async function onAnimationEnd(index) {
        if (_props.step) {
            await sleep((_props.interval || 1) * 1000);

            // 只有一条数据时，手动赋值下标为-1一下
            if (_props.list.length === 1) {
                current.value = -1;
                await sleep(20);
            }

            current.value = index + 1 >= _props.list.length ? 0 : index + 1;
        } else if (_props.interval) {
            await sleep(_props.interval * 1000);

            // 只有一条数据时，手动赋值下标为-1一下
            if (_props.list.length === 1) {
                current.value = -1;
                await sleep(20);
            }

            current.value = index + 1 >= _props.list.length ? 0 : index + 1;
        } else {
            // 只有一条数据时，手动赋值下标为-1一下
            if (_props.list.length === 1) {
                current.value = -1;
                await sleep(20);
            }

            current.value = index + 1 >= _props.list.length ? 0 : index + 1;
        }
    }

    // 计算滚动通知文本的样式
    const textsStyles = computed(() => {
        const styles = [];

        rects.value?.forEach((item, index) => {
            // 设置了滚动总市场
            if (_props?.duration) {
                styles.push(`--hi-notice-bar-animation-duration: ${_props.duration}s`);
            }

            // 设置了滚动速度
            else if (_props?.speed) {
                // 纵向
                if (!_props?.vertical) {
                    styles.push(`--hi-notice-bar-animation-duration: ${(item?.width || 0) / _props.speed}s`);
                }

                // 横向
                else {
                    styles.push(`--hi-notice-bar-animation-duration: ${(item?.height || 0) / _props.speed}s`);
                }
            }
        });

        return styles;
    });

    // 组件动画结束
    function onComponentAnimationEnd() {
        isShow.value = _props.show;
    }
</script>

<style lang="scss" scoped>
    .hi-notice-bar {
        display: var(--hi-notice-bar-display, flex);
        align-items: var(--hi-notice-bar-align-items, center);
        gap: var(--hi-notice-bar-gap, 5px);
        animation-duration: var(--hi-notice-bar-animation-duration, 100ms);
        animation-timing-function: var(--hi-notice-bar-animation-timing-function, linear);
        animation-fill-mode: forwards;
        animation-iteration-count: 1;
        transform-origin: var(--hi-notice-bar-transform-origin, center center);

        &__content {
            flex: var(--hi-notice-bar-content-flex, 1);
            position: var(--hi-notice-bar-content-position, relative);
            overflow: var(--hi-notice-bar-content-overflow, hidden);
            height: var(--hi-notice-bar-content-height, 1.5em);
            line-height: var(--hi-notice-bar-content-line-height, 1.5);
        }

        &__icon {
            color: var(--hi-notice-bar-icon-color, inherit);
            font-size: var(--hi-notice-bar-icon-font-size, 1.25em);

            &--arrow {
                color: var(--hi-notice-bar-arrow-color, inherit);
                font-size: var(--hi-notice-bar-arrow-font-size, 1.25em);
            }

            &--close {
                color: var(--hi-notice-bar-close-color, inherit);
                font-size: var(--hi-notice-bar-close-font-size, 1.25em);
            }
        }

        &__text {
            position: var(--hi-notice-bar-text-position, absolute);
            z-index: var(--hi-notice-bar-text-z-index, 8);
            transform: var(--hi-notice-bar-text-transform, none);
            animation-duration: var(--hi-notice-bar-animation-duration, 5s);
            animation-timing-function: var(--hi-notice-bar-animation-timing-function, linear);
            animation-iteration-count: var(--hi-notice-bar-animation-iteration-count, 1);
            animation-fill-mode: var(--hi-notice-bar-animation-fill-mode, forwards);
            min-width: 100%;
        }

        &--row {
            .hi-notice-bar__text {
                top: 50%;
                left: 100%;
                transform: translate(0, -50%);
                white-space: nowrap;
            }

            .hi-notice-bar__text--move-to {
                animation-name: hi-notice-bar-animate-row;
                transform: translate(-100%, -50%);
                left: 0;
                animation-duration: var(--hi-notice-bar-animation-duration, 5s);
            }
        }

        &--column {
            .hi-notice-bar__text {
                top: 100%;
                left: 0;
                transform: translate(0, 0);
                white-space: initial;
            }

            .hi-notice-bar__text--move-to {
                animation-name: hi-notice-bar-animate-column;
                transform: translate(0, -100%);
                top: 0;
                animation-duration: var(--hi-notice-bar-animation-duration, 2.5s);
            }
        }

        &--step {
            &.hi-notice-bar--row {
                .hi-notice-bar__text {
                    left: 100%;
                    white-space: initial;
                }

                .hi-notice-bar__text--move-to {
                    animation-name: hi-notice-bar-animate-row-step;
                    animation-duration: var(--hi-notice-bar-animation-duration, 1.5s);
                }
            }

            &.hi-notice-bar--column {
                .hi-notice-bar__text--move-to {
                    animation-name: hi-notice-bar-animate-column-step;
                    animation-duration: var(--hi-notice-bar-animation-duration, 0.5s);
                }
            }
        }

        &--hide {
            animation-name: hi-notice-bar-animate-hide;
        }

        &--show {
            animation-name: hi-notice-bar-animate-show;
        }
    }

    @keyframes hi-notice-bar-animate-row {
        0% {
            left: 100%;
            transform: translate(0, -50%);
        }
        100% {
            left: 0;
            transform: translate(-100%, -50%);
        }
    }

    @keyframes hi-notice-bar-animate-column {
        0% {
            top: 100%;
            transform: translate(0, 0);
        }
        100% {
            top: 0;
            transform: translate(0, -100%);
        }
    }

    @keyframes hi-notice-bar-animate-row-step {
        0% {
            left: 100%;
            transform: translate(0, -50%);
        }
        100% {
            left: 0;
            transform: translate(0, -50%);
        }
    }

    @keyframes hi-notice-bar-animate-column-step {
        0% {
            top: 100%;
            transform: translate(0, 0);
        }
        100% {
            top: 0;
            transform: translate(0, 0);
        }
    }

    @keyframes hi-notice-bar-animate-hide {
        0% {
            transform: scaleY(1);
            overflow: hidden;
        }
        100% {
            transform: scaleY(0);
            opacity: 0;
        }
    }

    @keyframes hi-notice-bar-animate-show {
        0% {
            transform: scaleY(0);
            opacity: 0;
        }
        100% {
            transform: scaleY(1);
            opacity: 1;
        }
    }
</style>
